﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;

namespace Undercover.Model
{
    public enum RuleVersion
    {
        V0,
    };

    public class WordPair
    {
        public string MajorityWord { get; set; }
        public string MinorityWord { get; set; }
        public bool CanSwap { get; set; }
        public int UseCount { get; set; }

        public WordPair CloneTo()
        {
            return new WordPair() { MajorityWord = this.MajorityWord, MinorityWord = this.MinorityWord, CanSwap = this.CanSwap, UseCount = this.UseCount };
        }

        public void Set(WordPair p)
        {
            MajorityWord = p.MajorityWord;
            MinorityWord = p.MinorityWord;
            CanSwap = p.CanSwap;
            UseCount = p.UseCount;
        }

        public override string ToString()
        {
            return String.Format("{0},{1},{2},{3}", MajorityWord, MinorityWord, CanSwap ? 1 : 0, UseCount);
        }

        public static WordPair NewEmpty()
        {
            WordPair ret = new WordPair()
            {
                MajorityWord = String.Empty,
                MinorityWord = String.Empty,
                CanSwap = true,
                UseCount = 0
            };
            return ret;
        }

        public static WordPair Parse(string str)
        {
            if (String.IsNullOrEmpty(str)) return null;

            string[] items = str.Split(',');
            if (items.Length != 4) return null;
            if (items[0].Length != items[1].Length) return null;
            if (items[2] != "0" && items[2] != "1") return null;

            WordPair ret = new WordPair();
            ret.MajorityWord = items[0];
            ret.MinorityWord = items[1];
            ret.CanSwap = (items[2] == "1");
            ret.UseCount = int.Parse(items[3]);

            return ret;
        }

        public static bool IsNullOrEmpty(WordPair p)
        {
            return p == null || String.IsNullOrEmpty(p.MajorityWord) || String.IsNullOrEmpty(p.MinorityWord);
        }

        public override bool Equals(object obj)
        {
            if (obj == null)
            {
                return false;
            }

            WordPair wp = obj as WordPair;
            if (wp == null)
            {
                return false;
            }

            return (MajorityWord == wp.MajorityWord && MinorityWord == wp.MinorityWord)
                || (MajorityWord == wp.MinorityWord && MinorityWord == wp.MajorityWord);
        }

        public override int GetHashCode()
        {
            return MajorityWord.GetHashCode() | MinorityWord.GetHashCode();
        }
    }

    public class WordPairList : List<WordPair>, IXmlSerializable
    {
        public override string ToString()
        {
            return String.Join(";", this.Select(it => it.ToString()));
        }

        private void ParseAndAdd(string str)
        {
            foreach (var item in str.Split(';'))
            {
                WordPair p = WordPair.Parse(item);
                if (p != null)
                {
                    Add(p);
                }
            }
        }

        public static WordPairList Parse(string str)
        {
            if (String.IsNullOrEmpty(str)) return null;

            WordPairList ret = new WordPairList();
            ret.ParseAndAdd(str);
            return ret;
        }

        public System.Xml.Schema.XmlSchema GetSchema()
        {
            return null;
        }

        public void ReadXml(System.Xml.XmlReader reader)
        {            
            if (reader.Read() && reader.NodeType == System.Xml.XmlNodeType.Element && reader.Name == "Length")
            {
                reader.Read();
                int length = reader.ReadContentAsInt();
                if (reader.Read() && reader.NodeType == System.Xml.XmlNodeType.Element && reader.Name == "Content")
                {
                    reader.Read();
                    Byte[] secure = new Byte[length];
                    reader.ReadContentAsBinHex(secure, 0, length);
                    Byte[] buf = ProtectedData.Unprotect(secure, null); ;
                    string str = UTF8Encoding.UTF8.GetString(buf, 0, buf.Length);
                    ParseAndAdd(str);
                    reader.Read();
                }
                reader.Read();
            }
        }

        public void WriteXml(System.Xml.XmlWriter writer)
        {
            Byte[] buf = UTF8Encoding.UTF8.GetBytes(this.ToString());
            Byte[] secure = ProtectedData.Protect(buf, null);
            writer.WriteStartElement("Length");
            writer.WriteValue(secure.Length);
            writer.WriteEndElement();
            writer.WriteStartElement("Content");
            writer.WriteBinHex(secure, 0, secure.Length);
            writer.WriteEndElement();
        }
    }
}
